package com.gf.gf_data.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;

/**
 * JWT 工具类
 *
 * Created by Eternal_L on 2018/1/9.
 */
public class JWTUtil {

    /**
     * token 加密秘钥
     */
    private static final String SECRET_KEY = "@@&.-001,-$***";

    /**
     * token 类型
     */
    public static final String TOKEN_TYPE = "bearer";

    /**
     * 请求头数据标记
     */
    public static final String HEADER_MARK = "Authorization";

    /**
     * 有效时间（毫秒）
     */
    public static final long TTL_MILLIS = 3600*1000;

    /**
     * 票据用户唯一标识
     */
    public static final String UNIQUE_NAME_KEY = "unique_name";

    /**
     * 用户记录ID
     */
    public static final String USER_ID = "user_id";

    /**
     * 新token在request中存储位置
     */
    public static final String REQ_TOKEN_MARK = "new_token";

    /**
     * 解析JWT token
     *
     * @param jsonWebToken    token
     * @param base64Security  秘钥
     * @return                Claims
     */
    public static Claims parseJWT(String jsonWebToken, String base64Security) {
        try {
//            String[] jwtArr = jsonWebToken.split("\\.");
//            System.out.println("jwtArr.length : " + jwtArr.length);
//            // token 结构必须满足格式：***.***.***
//            if (jwtArr.length == 3) {
//                System.out.println("sign = " + jwtArr[2]);
//                // 获取负荷信息
//                Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
//                        .parseClaimsJws(jsonWebToken).getBody();
//                // 检查数据是否被篡改
//                String newSign = createJWT(
//                        claims.get(UNIQUE_NAME_KEY).toString(),
//                        claims.get(USER_ID).toString(),
//                        JWTUtil.TTL_MILLIS,
//                        JWTUtil.getBase64SecretKey()).split("\\.")[2];
//                System.out.println("newSign = " + newSign);
//                // 比较两次秘钥是否相同
//                if (newSign.equals(jwtArr[2])) return claims;
//            }
            return Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
                        .parseClaimsJws(jsonWebToken).getBody();
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }


    /**
     * 创建 token
     *
     * @param uniqueName       唯一标识
     * @param userId           账户ID
     * @param expire           有效时间
     * @param base64Security   base64加密后的秘钥
     * @return                 token字符串
     */
    public static String createJWT(String uniqueName, String userId, long expire, String base64Security) {
        // 指定签名算法
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 获取当前时间
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        // 生成签名密钥
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        // 设置构成JWT的参数
        JwtBuilder builder = Jwts.builder()
                .setHeaderParam("typ", "JWT")         // 设置Header
                .setHeaderParam("alg", "HS256")
                .claim(UNIQUE_NAME_KEY, uniqueName)        // 存入唯一标识
                .claim(USER_ID, userId)                    // 存入用户ID
                .signWith(signatureAlgorithm, signingKey); // 签名

        // 设置token过期时间
        if (expire >= 0) {
            long expMillis = nowMillis + expire;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp).setNotBefore(now);
        }

        //生成返回JWT token
        return builder.compact();
    }

    /**
     * Base64 秘钥
     * @return secretKeyString
     */
    public static String getBase64SecretKey(){
        return Arrays.toString(Base64.getEncoder().encode(SECRET_KEY.getBytes()));
    }

}
